package com.gfl.trivialrestclient.controllers;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import com.gfl.trivialrestclient.controllers.validators.ProductValidator;
import com.gfl.trivialrestclient.model.Product;
import com.gfl.trivialrestclient.services.ProductService;
import com.gfl.trivialrestclient.services.ProductServiceException;

@Controller
public class ProductController {
	private final Log log = LogFactory.getLog(getClass());

	private ProductService productService;

	@Autowired
	public void setProductService(ProductService productService) {
		this.productService = productService;
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"yyyy-MM-dd HH:mm:ss");
		binder.registerCustomEditor(Date.class, new CustomDateEditor(
				dateFormat, false));

		binder.setValidator(new ProductValidator());
	}

	@ModelAttribute("product")
	public Product defaultProduct() {
		return new Product.Builder().name("product name").weight(100.0)
				.units(1).addedNow().build();
	}

	@RequestMapping(value = "product/view/{id}")
	public String viewSpecificProduct(@PathVariable("id") Long id, Model model) {
		if (id == null) {
			String message = "Product id must be not null";
			log.error(message);
			model.addAttribute("message", message);

			return "error";
		}

		Product product = productService.read(id);
		model.addAttribute("product", product);

		return "viewSingleProduct";
	}

	@RequestMapping(value = "product/view")
	public String viewProducts(Model model) {
		List<Product> products = productService.readAll();
		model.addAttribute("products", products);

		return "viewProducts";
	}

	@RequestMapping(value = "product/create", method = RequestMethod.GET)
	public String createProduct(@ModelAttribute("product") Product product,
			Model model, BindingResult result) {

		return "createProduct";
	}

	@RequestMapping(value = "product/create", method = RequestMethod.POST)
	public String saveCreatedProduct(
			@Valid @ModelAttribute("product") Product product,
			BindingResult result, Model model) {
		if (result.hasErrors()) {
			return "createProduct";
		}

		productService.create(product);

		return "redirect:/product/view";
	}

	@RequestMapping(value = "product/edit/{id}", method = RequestMethod.GET)
	public String editSpecificProduct(@PathVariable("id") Long id, Model model) {
		if (id == null) {
			String message = "Product id must be not null";
			log.error(message);
			model.addAttribute("message", message);

			return "error";
		}

		Product product = productService.read(id);
		model.addAttribute("product", product);

		return "editSingleProduct";
	}

	@RequestMapping(value = "product/edit/{id}", method = RequestMethod.POST)
	public String saveEditedProduct(@PathVariable("id") Long id,
			@Valid @ModelAttribute("product") Product product,
			BindingResult result, Model model) {
		if (id == null) {
			String message = "Product id must be not null";
			log.error(message);
			model.addAttribute("message", message);

			return "error";
		}

		productService.edit(id, product);

		return "redirect:/product/view";
	}

	@RequestMapping(value = "product/edit")
	public String editProducts(Model model) {
		List<Product> products = productService.readAll();
		model.addAttribute("products", products);

		return "editProducts";
	}

	@RequestMapping(value = "product/remove")
	public String deleteProducts(Model model) {
		List<Product> products = productService.readAll();
		model.addAttribute("products", products);

		return "deleteProducts";
	}

	@RequestMapping(value = "product/remove/{id}")
	public String deleteSpecificProduct(@PathVariable("id") Long id, Model model) {
		if (id == null) {
			String message = "Product id must be not null";
			log.error(message);
			model.addAttribute("message", message);

			return "error";
		}

		productService.delete(id);

		return "redirect:/product/view";
	}

	@ExceptionHandler(value = { RuntimeException.class, ServletException.class,
			ProductServiceException.class })
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public ModelAndView handleExceptions(Exception ex) {
		log.error("Error in ProductCntroller." + ex.getClass().getName(), ex);

		ModelAndView mav = new ModelAndView("error");
		mav.addObject("messsage", "Product manipulation error");
		return mav;
	}
}
